package com.starryx.websocket.chatroom.net;

import com.starryx.websocket.chatroom.net.handler.HttpRequestHandler;
import com.starryx.websocket.chatroom.net.handler.TextWebSocketFrameHandler;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.handler.stream.ChunkedWriteHandler;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.util.concurrent.atomic.AtomicBoolean;

public class ChatroomServer {

    private static final Logger log = LogManager.getLogger(ChatroomServer.class);

    private String ip;

    private int port;

    private EventLoopGroup bossGroup;

    private EventLoopGroup workerGroup;

    private AtomicBoolean isRunning = new AtomicBoolean(false);

    public ChatroomServer(String ip, int port, int bossGroupThreadNum, int workerGroupThreadNum) {
        this.ip = ip;
        this.port = port;
        this.bossGroup = new NioEventLoopGroup(bossGroupThreadNum);
        this.workerGroup = new NioEventLoopGroup(workerGroupThreadNum);
    }

    public void start() {
        if (!this.isRunning.compareAndSet(false, true)) {
            log.info("Server 已经启动");
        } else {
            try {
                ServerBootstrap bootstrap = new ServerBootstrap();
                bootstrap.group(this.bossGroup, this.workerGroup)
                        .channel(NioServerSocketChannel.class)
                        .childOption(ChannelOption.TCP_NODELAY, true)
                        .childOption(ChannelOption.SO_KEEPALIVE, true)
                        .option(ChannelOption.SO_BACKLOG, 128)
                        .childHandler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel socketChannel) throws Exception {
                        ChannelPipeline channelPipeline = socketChannel.pipeline();
                        channelPipeline
                                .addLast("codec", new HttpServerCodec())
                                .addLast("aggregator", new HttpObjectAggregator(512 * 1024))
                                .addLast(new ChunkedWriteHandler())
                                .addLast("handler", new HttpRequestHandler("/ws"))
                                .addLast(new WebSocketServerProtocolHandler("/ws"))
                                .addLast(new TextWebSocketFrameHandler());
                    }
                });
                bootstrap.bind(ip, port).sync();
            } catch (Exception e) {
                this.shutdown();
            }
        }
    }

    public void shutdown() {
        if (!this.isRunning.compareAndSet(true, false)) {
            log.info("Server 已经关闭");
        }

        try {
            this.bossGroup.shutdownGracefully().sync();
            this.workerGroup.shutdownGracefully().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
